package com.suning.sawp.service.impl.job;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.suning.framework.dal.client.DalClient;
import com.suning.nsfuaa.employee.dto.EmployeeInfo;
import com.suning.sawp.cache.RedisClient;
import com.suning.sawp.constants.CacheKeyConstants;
import com.suning.sawp.constants.ClerkConstants;
import com.suning.sawp.constants.ConfigConstants;
import com.suning.sawp.dto.customer.CustInfoDetailDto;
import com.suning.sawp.dto.mainpush.StoreManDto;
import com.suning.sawp.dto.promotion.InnerCouponBlackList;
import com.suning.sawp.intf.bi.BiKafkaRealTimeSaleService;
import com.suning.sawp.intf.bi.BiSaleAmountDaoService;
import com.suning.sawp.intf.dao.BiKafkaRealTimeSaleDaoService;
import com.suning.sawp.intf.dao.IndexCardTaskDaoService;
import com.suning.sawp.intf.dao.coupon.InnerCouponDaoService;
import com.suning.sawp.intf.esb.MemberInfoService;
import com.suning.sawp.intf.job.BiDataJobService;
import com.suning.sawp.intf.store.StoreInfoService;
import com.suning.sawp.intf.storeman.StoreManService;
import com.suning.sawp.po.bi.BIIndexTaskCardEntity;
import com.suning.sawp.po.bi.BiStoreMonSaleTask;
import com.suning.sawp.po.bi.StoreManDevMemberDetail;
import com.suning.sawp.po.customer.ClerkCustInfo;
import com.suning.sawp.service.impl.customer.ClerkCustRelService;
import com.suning.sawp.service.util.DJStringUtils;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.SCMConfigUtil;
import com.suning.vgs.follow.remote.intf.StoreManRemoteService;
import com.suning.vgs.follow.remote.store.ClerkCustomerDevRetDto;

@Service("biDataJobService")
public class BiDataJobServiceImpl implements BiDataJobService  {

    private static final Logger LOGGER = LoggerFactory.getLogger(BiDataJobServiceImpl.class);
    
    /**
     * 默认门店编码
     */
    private static final String DEF_STORE_CODE = "7320";
    
    /**
     * 一键注册渠道
     */
    private static final String ONLINE_AND_OFFLINE_CHANNEL = "3";
    
    /**
     * 门店店长和副店长集合
     */
    private static final String STORE_KEEP_POSITION = "00000290,00000291";
    
    @Resource
    DalClient dalClient;
    
    @Resource
    MemberInfoService memberInfoService;
    
    @Resource
    ClerkCustRelService clerkCustRelService;
    
    @Resource
    StoreManRemoteService storeManRemoteService;
    
    @Resource
    StoreManService storeManService;
    
    @Resource
    BiSaleAmountDaoService biSaleAmountDaoService;
    
    @Resource
    IndexCardTaskDaoService indexCardTaskDaoService;
    
    @Resource
    StoreInfoService storeInfoService;
    
    @Resource
    BiKafkaRealTimeSaleDaoService biKafkaRealTimeSaleDaoService;
    
    @Resource
    BiKafkaRealTimeSaleService biKafkaRealTimeSaleService;
    
    @Resource
    InnerCouponDaoService innerCouponDaoService;
    
    @Autowired
    RedisClient redisClient;
    
 // kafka topic
    @Value("#{settingConfig[kafka_topic]}")
    String topic;
    // 分区数
    @Value("#{settingConfig[kafka_partitionsNum]}")
    int partitionsNum;
    @Value("#{settingConfig[kafka_zk_connect]}")
    String kafkaZkConnect;

    @Value("#{settingConfig[kafka_group_id]}")
    String kafkaGroupId;

    @Value("#{settingConfig[kafka_zk_session_timeout_ms]}")
    String kafkaZkSessionTimeout;

    @Value("#{settingConfig[kafka_zk_sync_time_ms]}")
    String kafkaZkSyncTime;

    @Value("#{settingConfig[kafka_auto_commit_interval_ms]}")
    String kafkaAutoCommitInterval;
    
//    @Autowired
//    BiStoreRealTimeSaleKafkaConsumer biStoreRealTimeSaleKafkaConsumer;
    
    @Override
    public void deleteExpireRetGdsData() {
        // 取昨天日期
        Date yestd = DateUtils.getNextDay(new Date(), -1);
        String yestdStr = DateUtils.getDateStrByFormat(yestd, DateUtils.YYYYMMDD_PATTERN);
        String last60DayStr = DateUtils.getDateStrByFormat(
                DateUtils.getNextDay(yestd, -60), DateUtils.YYYYMMDD_PATTERN);
        String last14DayStr = DateUtils.getDateStrByFormat(
                DateUtils.getNextDay(yestd, -14), DateUtils.YYYYMMDD_PATTERN);
        // 考虑到Java 和 SQL 对于所在周的算法不同, 往前推9周
        Date date = DateUtils.getNextDay(yestd, -63);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int week = calendar.get(Calendar.WEEK_OF_YEAR);
        int year = calendar.get(Calendar.YEAR);
        
        // 取昨天所在月份，往前推6个月
        Calendar cal = Calendar.getInstance();
        cal.setTime(yestd);
        cal.add(Calendar.MONTH, -5);
        Date last6Mon = cal.getTime();
        String last6MonStr = DateUtils.getDateStrByFormat(last6Mon, DateUtils.YYYYMM_PATTERN);

        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("yesterday", yestdStr);
        paramMap.put("last14Day", last14DayStr);
        paramMap.put("last60Day", last60DayStr);
        paramMap.put("last6Mon", last6MonStr);
        paramMap.put("week", week);
        paramMap.put("year", year);
        // 1、门店退货月统计BI_STORE_RET_GDS_MONTH 保留最近6个月数据，超过删除
        dalClient.execute("BI_STORE_RET_GDS_MONTH.DELETE_EXPIRE_DATA", paramMap);
        // 2、门店-品类退货月统计BI_STORE_CATE_RET_GDS_MONTH 保留最近6个月数据，超过删除
        dalClient.execute("BI_STORE_CATE_RET_GDS_MONTH.DELETE_EXPIRE_DATA", paramMap);
        // 3、门店退货日统计 BI_STORE_RET_GDS_DAY 保留60天数据，超过删除
        dalClient.execute("BI_STORE_RET_GDS_DAY.DELETE_EXPIRE_DATA", paramMap);
        // 4、门店-品类退货日统计 BI_STORE_CATE_RET_GDS_DAY 保留14天数据，超过删除
        dalClient.execute("BI_STORE_CATE_RET_GDS_DAY.DELETE_EXPIRE_DATA", paramMap);
        // 5、门店-品类退货周统计 BI_STORE_CATE_RET_GDS_WEEK 保留8周的数据，超过删除
        dalClient.execute("BI_STORE_CATE_RET_GDS_WEEK.DELETE_EXPIRE_DATA", paramMap);
    }

    @Override
    public void dealOldMemberData() {
        LOGGER.info("dealOldMemberData begin");
        Long rateId = Long.valueOf(SCMConfigUtil.getConfig(ConfigConstants.DEFAULT_RATE_ID));
        // 处理POS开单的老功能原先的老会员数据
        // STORE_REG_MEMBER_DETAIL_D POS渠道的会员
        Integer count = dalClient.queryForObject("STORE_REG_MEMBER_DETAIL_D.COUNT_TOTAL_SIZE", null, Integer.class);
        LOGGER.info("dealOldMemberData STORE_REG_MEMBER_DETAIL_D size:{}", count);
        int pageSize = 50;
        int pageTot = count / pageSize + 1;
        for (int i = 0; i < pageTot; i++) {
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("startIndex", i);
            paramMap.put("limit", (i + 1) * pageSize);
            List<StoreManDevMemberDetail> list = dalClient.queryForList("STORE_REG_MEMBER_DETAIL_D.QUERY_RECORDS_PAGE", paramMap, StoreManDevMemberDetail.class);
            List<String> custNoList = new ArrayList<String>();
            List<StoreManDevMemberDetail> details = new ArrayList<StoreManDevMemberDetail>();
            for (StoreManDevMemberDetail detail : list) {
                if ("pos".equals(detail.getMemberSourceCode())) {
                    // 已处理POS渠道的
                    custNoList.add(detail.getMemberId());
                    details.add(detail);
                }
            }
            
            // 会员手机号
            Map<String, String> custMobiles = memberInfoService.getMemberMobiles(custNoList);
            for (StoreManDevMemberDetail detail : details) {
                String account = custMobiles.get(detail.getMemberId());
                if (StringUtils.isNotBlank(account)) {
                    CustInfoDetailDto detailDto = new CustInfoDetailDto();
                    // 客户评级给C
                    detailDto.setRateId(rateId);
                    // 会员编码
                    detailDto.setCustNo(detail.getMemberId());
                    // 客户来源
                    detailDto.setCustSource(ClerkCustInfo.CustSource.POS);
                    // 非重点客户
                    detailDto.setIsKeyCust(ClerkCustInfo.KeyCustOpType.CANCEL_KEY);
                    // 手机号
                    detailDto.setMobile(account);
                    // 工号
                    detailDto.setStaffId(detail.getEmployeeCode());
                    // 门店编码
                    detailDto.setStoreCode(detail.getStoreCode());
                    // 记录创建时间
                    detailDto.setCreateTime(detail.getOnlineCreateTime());
                    // 备注名，注册为手机号，以脱敏手机号作为用户名
                    detailDto.setRemarkName(DJStringUtils.desensitiseMobile(account));
                    clerkCustRelService.addClerkCustRelWhenNoOutGrow(detailDto);
                }
            }
        }
        
        // 处理店+渠道的老数据
        int startIndex = 0;
        int limit = 20;
        String cutOffTime = SCMConfigUtil.getConfig("cutOffTime");
        Date dateTime = DateUtils.getDateByStr(cutOffTime, DateUtils.DEFAULT_TIME_PATTERN);
        List<ClerkCustomerDevRetDto> list = storeManRemoteService.queryClerkCustomerDevData(startIndex, limit, dateTime);
        while (CollectionUtils.isNotEmpty(list)) {
            for (ClerkCustomerDevRetDto dto : list) {
                StoreManDto manDto = storeManService.queryStoreManAttachInfo(dto.getClerkNo());
                if (null != manDto && StringUtils.isNotBlank(manDto.getStoreCode())) {
                 // 如果门店编码为默认门店编码，且注册来源为一键注册，因为无法分辨此会员是否为该门店真实员工注册，舍弃此条记录不计入店员客户关系表中
                    if (!(DEF_STORE_CODE.equals(manDto.getStoreCode()) 
                            && ONLINE_AND_OFFLINE_CHANNEL.equals(dto.getChannel()))
                            && (!manDto.getStoreCode().startsWith("TS@"))) {
                        CustInfoDetailDto detailDto = new CustInfoDetailDto();
                        // 客户评级给C
                        detailDto.setRateId(rateId);
                        // 会员编码
                        detailDto.setCustNo(dto.getCustNo());
                        // 客户来源
                        detailDto.setCustSource(ClerkCustInfo.CustSource.ONE_KEY_REG);
                        // 非重点客户
                        detailDto.setIsKeyCust(ClerkCustInfo.KeyCustOpType.CANCEL_KEY);
                        // 手机号
                        detailDto.setMobile(dto.getMobile());
                        // 工号
                        detailDto.setStaffId(dto.getClerkNo());
                        // 门店编码
                        detailDto.setStoreCode(manDto.getStoreCode());
                        // 记录创建时间
                        detailDto.setCreateTime(dto.getCreateTime());
                        // 备注名，注册为手机号，以脱敏手机号作为用户名
                        detailDto.setRemarkName(DJStringUtils.desensitiseMobile(dto.getMobile()));
                        clerkCustRelService.addClerkCustRelWhenNoOutGrow(detailDto);
                    }
                }
            }
            startIndex += limit;
            list = storeManRemoteService.queryClerkCustomerDevData(startIndex, limit, dateTime);
        }
    }

    @Override
    public void dealStoreRealSaleToIndexShow() {
        LOGGER.info("BiDataJobService.dealStoreRealSaleToIndexShow in");
        // 取上个月月份
        String lastMonth = DateUtils.getLastMonth();
        // 今日零点时间
        Date todayZeroPiont = DateUtils.getZeroPoint(DateUtils.getNextDay(new Date(), -1));
        // 查询上个月所有门店的销售记录,100条记录一批次
        int startIndex = 0;
        int limit = 100;
        List<BiStoreMonSaleTask> list =  biSaleAmountDaoService.queryLastMonStoreRealSale(lastMonth, startIndex, limit);
        while (CollectionUtils.isNotEmpty(list)) {
            LOGGER.info("BiDataJobService.dealStoreRealSaleToIndexShow startIndex:{}", startIndex);
            dealStoreRealSaleOneBatch(list, lastMonth, todayZeroPiont);
            startIndex += limit;
            list = biSaleAmountDaoService.queryLastMonStoreRealSale(lastMonth, startIndex, limit);
        }
        LOGGER.info("BiDataJobService.dealStoreRealSaleToIndexShow out");
    }

    /**
     * 
     * 功能描述: 处理一个批次门店实际销售在首页卡片中的数据<br>
     * 〈功能详细描述〉
     *
     * @param list
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private void dealStoreRealSaleOneBatch(List<BiStoreMonSaleTask> list, String lastMonth, Date yetdZeroPiont) {
        for (BiStoreMonSaleTask saleTask : list) {
            // 调用NSF-UUA，取门店对应的店长和副店长
            List<EmployeeInfo> eList = storeManService.getClerksInStoretiByStoreCd(saleTask.getStoreCode(), STORE_KEEP_POSITION);
            for (EmployeeInfo employeeInfo : eList) {
                if (null != saleTask.getGrossProfit() && null != saleTask.getGrossCompleteRate()
                        && null != saleTask.getEtlTime() && yetdZeroPiont.before(saleTask.getEtlTime())) {
                    // 实际毛利和毛利完成率不为空，且etlTime为昨天零点之后的时间
                    BigDecimal grossProfit = saleTask.getGrossProfit().divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP);
                    BigDecimal grossCompleteRate = saleTask.getGrossCompleteRate().multiply(new BigDecimal(100)).setScale(1, BigDecimal.ROUND_HALF_UP);
                    Date date = DateUtils.getDateByStr(saleTask.getMonth(), DateUtils.YYYYMM_PATTERN);
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(date);
                    int month = cal.get(Calendar.MONTH) + 1;
                    String[] args = {String.valueOf(month), grossProfit.toPlainString(), grossCompleteRate.toPlainString()};
                    String tips = getCardTips(args, ClerkConstants.MON_SALE_CARD_TIPS);
                    if (StringUtils.isBlank(tips)) {
                        continue;
                    }
                    // 设置对应门店相应的店长和副店长的首页卡片展示
                    BIIndexTaskCardEntity entity = new BIIndexTaskCardEntity();
                    // 门店月度销售
                    entity.setBizKey(BIIndexTaskCardEntity.BizKey.STORE_MON_SALE);
                    // 卡片类型
                    entity.setCardType(BIIndexTaskCardEntity.CardType.CARD_002);
                    // 任务卡片分配的人员
                    entity.setStaffId(employeeInfo.getEmployeeId());
                    // 任务卡片开始时间  用当前时间
                    entity.setStartTime(new Date());
                    // 任务结束结束时间  开始时间往后推三天
                    entity.setEndTime(DateUtils.getNextDay(new Date(), 3));
                    // 卡片提示
                    entity.setTaskTips(tips);
                    // 卡片标题
                    entity.setTitle(BIIndexTaskCardEntity.Title.STORE_MON_SALE);
                    indexCardTaskDaoService.upsertIndexTaskCard(entity);
                }
            }
        }
    }
    
    /**
     * 
     * 功能描述: 卡片tips转换<br>
     * 〈功能详细描述〉
     *
     * @param args
     * @param tipsFormat
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private String getCardTips(String[] args, String tipsFormat) {
        String tips = null;
        try {
            MessageFormat form = new MessageFormat(tipsFormat);
            tips = form.format(args);
        } catch (Exception e) {
            LOGGER.error("BiDataJobService.getCardTips format fail. args:{}, tipsFormat:{}", args, tipsFormat, e);
        }
        return tips;
    }

    @Override
    public void dealStoreRealTimeSale2DB() {
        biKafkaRealTimeSaleService.perisitCacheSaleData();
    }

    @Override
    public void dealStoreHalfHourSaleCopy() {
        biKafkaRealTimeSaleService.copyHalfHourCacheSaleData();
    }

    @Override
    public void initBlackList() {
        // 循环取出所有黑名单，加入缓存中，缓存不设置失效时间，一直有效
        int total = innerCouponDaoService.queryBlackListCount(null);
        int pageSize = 10;
        int totalPageNum = (total / pageSize) + 1;
        List<InnerCouponBlackList> allList = new ArrayList<InnerCouponBlackList>();
        for (int i = 1; i <= totalPageNum; i++) {
            List<InnerCouponBlackList> itemList = innerCouponDaoService.queryBlackList(null, pageSize, i);
            if (CollectionUtils.isNotEmpty(itemList)) {
                allList.addAll(itemList);
            }
        }
        for (InnerCouponBlackList blackList : allList) {
            redisClient.hset(CacheKeyConstants.INNER_COUPON_BLACK_LIST, blackList.getStaffId(), "");
        }
    }
}
